/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Martin Taal - reworked for simpler use case (see class comments) *******************************************************************************/ package org.eclipse.emf.texo.generator; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.ArrayType; import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldAccess; import org.eclipse.jdt.core.dom.ImportDeclaration; import org.eclipse.jdt.core.dom.MarkerAnnotation; import org.eclipse.jdt.core.dom.MemberRef; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.MethodRef; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.PackageDeclaration; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.QualifiedType; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.eclipse.jdt.core.dom.SuperConstructorInvocation; import org.eclipse.jdt.core.dom.TagElement; import org.eclipse.jdt.core.dom.ThisExpression; /** * Is initially copied from * org.eclipse.jdt.internal.corext.codemanipulation.ImportReferencesCollector * and then adapted to work specifically for code generation where the code * generation contains fully qualified type names together with type names which * already have an import declaration. Other changes compared to the original * class: with the following changes: * <ul> * <li>Static imports are not supported.</li> * <li>No bindings are resolved, all type references are assumed to be fully * qualified or already imported.</li> * <li>No support for specific regions over which the import is done</li> * <li>Not possible to ignore method bodies</li> * </ul> * * @author <a href="mtaal@elver.org">Martin Taal</a> */ public class ImportReferencesCollector extends ASTVisitor { public static void collect(final ASTNode node, final IJavaProject project, final Collection<Name> resultingTypeImports) { ASTNode root = node.getRoot(); CompilationUnit astRoot = root instanceof CompilationUnit ? (CompilationUnit) root : null; node.accept(new ImportReferencesCollector(project, astRoot, resultingTypeImports)); } private Collection<Name> fTypeImports; private ImportReferencesCollector(final IJavaProject project, final CompilationUnit astRoot, final Collection<Name> resultingTypeImports) { super(processJavadocComments(astRoot)); fTypeImports = resultingTypeImports; } private static boolean processJavadocComments(final CompilationUnit astRoot) { // don't visit Javadoc for 'package-info' (bug 216432) if (astRoot != null && astRoot.getTypeRoot() != null) { return !"package-info.java".equals(astRoot.getTypeRoot().getElementName()); //$NON-NLS-1$ } return true; } private void addReference(final SimpleName name) { fTypeImports.add(name); } private void typeRefFound(Name node) { if (node != null) { while (node.isQualifiedName()) { node = ((QualifiedName) node).getQualifier(); } addReference((SimpleName) node); } } private void possibleTypeRefFound(Name node) { while (node.isQualifiedName()) { node = ((QualifiedName) node).getQualifier(); } addReference((SimpleName) node); } private void doVisitChildren(final List<?> elements) { int nElements = elements.size(); for (int i = 0; i < nElements; i++) { ((ASTNode) elements.get(i)).accept(this); } } private void doVisitNode(final ASTNode node) { if (node != null) { node.accept(this); } } /* * @see ASTVisitor#visit(ArrayType) */ @Override public boolean visit(final ArrayType node) { doVisitNode(node.getElementType()); return false; } /* * @see ASTVisitor#visit(SimpleType) */ @Override public boolean visit(final SimpleType node) { typeRefFound(node.getName()); return false; } /* * @see ASTVisitor#visit(QualifiedType) */ @Override public boolean visit(final QualifiedType node) { // nothing to do here, let the qualifier be visited return true; } /* * @see ASTVisitor#visit(QualifiedName) */ @Override public boolean visit(final QualifiedName node) { possibleTypeRefFound(node); // possible ref return false; } /* * @see ASTVisitor#visit(ImportDeclaration) */ @Override public boolean visit(final ImportDeclaration node) { return false; } /* * @see ASTVisitor#visit(PackageDeclaration) */ @Override public boolean visit(final PackageDeclaration node) { if (node.getAST().apiLevel() >= AST.JLS3) { doVisitNode(node.getJavadoc()); doVisitChildren(node.annotations()); } return false; } /* * @see ASTVisitor#visit(ThisExpression) */ @Override public boolean visit(final ThisExpression node) { typeRefFound(node.getQualifier()); return false; } private void evalQualifyingExpression(final Expression expr, final Name selector) { if (expr != null) { if (expr instanceof Name) { Name name = (Name) expr; possibleTypeRefFound(name); } else { expr.accept(this); } } } /* * @see ASTVisitor#visit(ClassInstanceCreation) */ @Override public boolean visit(final ClassInstanceCreation node) { doVisitChildren(node.typeArguments()); doVisitNode(node.getType()); evalQualifyingExpression(node.getExpression(), null); if (node.getAnonymousClassDeclaration() != null) { node.getAnonymousClassDeclaration().accept(this); } doVisitChildren(node.arguments()); return false; } /* * @see ASTVisitor#endVisit(MethodInvocation) */ @Override public boolean visit(final MethodInvocation node) { evalQualifyingExpression(node.getExpression(), node.getName()); doVisitChildren(node.typeArguments()); doVisitChildren(node.arguments()); return false; } /* * @see ASTVisitor#visit(SuperConstructorInvocation) */ @Override public boolean visit(final SuperConstructorInvocation node) { evalQualifyingExpression(node.getExpression(), null); doVisitChildren(node.typeArguments()); doVisitChildren(node.arguments()); return false; } /* * @see ASTVisitor#visit(FieldAccess) */ @Override public boolean visit(final FieldAccess node) { evalQualifyingExpression(node.getExpression(), node.getName()); return false; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse. * jdt.core.dom.MarkerAnnotation) */ @Override public boolean visit(final MarkerAnnotation node) { typeRefFound(node.getTypeName()); return false; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse. * jdt.core.dom.MarkerAnnotation) */ @Override public boolean visit(final NormalAnnotation node) { typeRefFound(node.getTypeName()); doVisitChildren(node.values()); return false; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse. * jdt.core.dom.MarkerAnnotation) */ @Override public boolean visit(final SingleMemberAnnotation node) { typeRefFound(node.getTypeName()); doVisitNode(node.getValue()); return false; } /* * @see ASTVisitor#visit(MethodDeclaration) */ @Override public boolean visit(final MethodDeclaration node) { doVisitNode(node.getJavadoc()); if (node.getAST().apiLevel() >= AST.JLS3) { doVisitChildren(node.modifiers()); doVisitChildren(node.typeParameters()); } if (!node.isConstructor()) { doVisitNode(node.getReturnType2()); } doVisitChildren(node.parameters()); Iterator<?> iter = node.thrownExceptions().iterator(); while (iter.hasNext()) { typeRefFound((Name) iter.next()); } doVisitNode(node.getBody()); return false; } @Override public boolean visit(final TagElement node) { String tagName = node.getTagName(); List<?> list = node.fragments(); int idx = 0; if (tagName != null && !list.isEmpty()) { Object first = list.get(0); if (first instanceof Name) { if ("@throws".equals(tagName) || "@exception".equals(tagName)) { //$NON-NLS-1$//$NON-NLS-2$ typeRefFound((Name) first); } else if ("@see".equals(tagName) || "@link".equals(tagName) || "@linkplain".equals(tagName)) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ Name name = (Name) first; possibleTypeRefFound(name); } idx++; } } for (int i = idx; i < list.size(); i++) { doVisitNode((ASTNode) list.get(i)); } return false; } @Override public boolean visit(final MemberRef node) { Name qualifier = node.getQualifier(); if (qualifier != null) { typeRefFound(qualifier); } return false; } @Override public boolean visit(final MethodRef node) { Name qualifier = node.getQualifier(); if (qualifier != null) { typeRefFound(qualifier); } List<?> list = node.parameters(); if (list != null) { doVisitChildren(list); // visit MethodRefParameter with Type } return false; } }